﻿using System;
using System.Collections.Generic;
using System.Text;
using System.IO;

using System.Text.RegularExpressions;
using System.Threading;

namespace FARAgent
{
    // Find And Replace Engine
    public class FAREngine
    {
        //private Thread m_Thread;
        private Regex m_Regex;
        private Match m_Match;

        public Boolean IsFirstFind { get; set; }

        // InitializeCriteria
        public string SearchForString { get; set; }
        public string ReplaceWithString { get; set; }
        public string Criteria { get; set; }

        // Regex Options
        public Boolean IsMatchWholeWord { get; set; }
        public Boolean IsUseWildcards { get; set; }
        public Boolean IsIgnoreCase { get; set; }
        public Boolean IsCultureInvariant { get; set; }
        public Boolean IsMultiLine { get; set; }
        public Boolean IsSingleLine { get; set; }
        public Boolean IsIndentedInput { get; set; }
        public Boolean IsUseRegulatExpression { get; set; }

        public FAREngine() 
        { }

        public FAREngine(string criteria)
        {
            this.Criteria = criteria;
        }

        private void InitializeCriteria (string criteria)
        {
            string[] _BuildCriteria = criteria.Split(';');

            this.SearchForString = _BuildCriteria[0];
            this.ReplaceWithString = _BuildCriteria[1];

            this.IsMatchWholeWord = System.Convert.ToBoolean(_BuildCriteria[2]);
            this.IsUseWildcards = System.Convert.ToBoolean(_BuildCriteria[3]);
            this.IsIgnoreCase = System.Convert.ToBoolean(_BuildCriteria[4]);
            this.IsCultureInvariant = System.Convert.ToBoolean(_BuildCriteria[5]);
            this.IsMultiLine = System.Convert.ToBoolean(_BuildCriteria[6]);
            this.IsSingleLine = System.Convert.ToBoolean(_BuildCriteria[7]);
            this.IsIndentedInput = System.Convert.ToBoolean(_BuildCriteria[8]);
            this.IsUseRegulatExpression = System.Convert.ToBoolean(_BuildCriteria[9]);

        }

        /// <summary>
        /// This function makes and returns a RegEx object
        /// depending on user input
        /// </summary>
        /// <returns></returns>
        public Regex GetRegExpression(string search)
        {
            Regex _Result;
            String _Search;
            RegexOptions _RegexOptions = new RegexOptions();

            // Get what the user entered
            _Search = search;

            if (this.IsUseRegulatExpression)
            {
                // If regular expressions checkbox is selected,
                // our job is easy. Just do nothing
            }
            // wild cards checkbox checked
            else if (this.IsUseWildcards)
            {
                _Search = _Search.Replace("*", @"\w*");     // multiple characters wildcard (*)
                _Search = _Search.Replace("?", @"\w");      // single character wildcard (?)

                // if wild cards selected, find whole words only
                _Search = String.Format("{0}{1}{0}", @"\b", _Search);
            }
            else
            {
                // replace escape characters
                _Search = Regex.Escape(_Search);
            }

            // Is whole word check box checked?
            if (IsMatchWholeWord)
            {
                _Search = String.Format("{0}{1}{0}", @"\b", _Search);
            }

            // Regex Options
            if (IsIgnoreCase) _RegexOptions = RegexOptions.IgnoreCase;
            if (IsCultureInvariant) _RegexOptions |= RegexOptions.CultureInvariant;
            if (IsMultiLine) _RegexOptions |= RegexOptions.Multiline;
            if (IsSingleLine) _RegexOptions |= RegexOptions.Singleline;
            if (IsIndentedInput) _RegexOptions |= RegexOptions.IgnorePatternWhitespace;

            if (IsIgnoreCase || IsCultureInvariant || IsMultiLine || IsSingleLine || IsIndentedInput)
            {
                _Result = new Regex(_Search, _RegexOptions);
            }
            else 
            {
                _Result = new Regex(_Search);            
            }

            return _Result;
        }

        /// <summary>
        /// finds the text in searchTextBox in contentTextBox
        /// </summary>
        public Match FindInContent(string content)
        {
            return FindInContent(content, this.Criteria);
        }
        
        public Match FindInContent(string content, string criteria)
        {
            if (content == null || content == "") return null;
            if (criteria == null || criteria == "") return null;

            InitializeCriteria(criteria);

            // Is this the first time find is called?
            // Then make instances of RegEx and Match
            if (IsFirstFind)
            {
                m_Regex = GetRegExpression(SearchForString);
                m_Match = m_Regex.Match(content);
                this.IsFirstFind = false;
            }
            else
            {
                // m_Match.NextMatch() is also ok, except in Replace
                // In replace as text is changing, it is necessary to
                // find again
                //m_Match = m_Match.NextMatch();
                m_Match = m_Regex.Match(content, m_Match.Index + 1);
            }

            // found a m_Match?
            if (!m_Match.Success)
            {
                this.IsFirstFind = true;
            }

            return m_Match;
        }

        public string ReplaceInContent(string content)
        { 
            return ReplaceInContent(content, this.Criteria);
        }

        public string ReplaceInContent(string content, string criteria)
        {
            if (content == null || content == "") return @"";
            if (criteria == null || criteria == "") return null;

            InitializeCriteria(criteria);

            m_Regex = GetRegExpression(SearchForString);
            String m_ReplacedResult;

            // get the replaced string
            m_ReplacedResult = m_Regex.Replace(content, ReplaceWithString);

            // Is the text changed, then replace it
            if (content != m_ReplacedResult)
                content = m_ReplacedResult;

            return content;
        }

    }
}
